﻿#include <fmt/args.h>
#include <fmt/format.h>
#include <fstream>
#include <gtest/gtest.h>

#include "IsoVortex.h"
#include "ReMeshApp.h"
#include <vtkm/cont/Algorithm.h>

struct IsoVortexTest : public ::testing::Test
{

  std::string Parallel(const std::string& type)
  {
    fmt::dynamic_format_arg_store<fmt::format_context> args;
    args.push_back(fmt::arg("type", type));

    std::string str_template = R"(
[Parallel]
    type = {type}
    num_threads = 8
[]
      )";

    return fmt::vformat(str_template, args);
  }

  std::string Mesh()
  {
    fmt::dynamic_format_arg_store<fmt::format_context> args;
    args.push_back(fmt::arg("type", "UnstructuredMesh"));

    std::string str_template = R"(
[Mesh]
    type = {type}
    dims = '100 100'
    x_range = '-10 10'
    y_range = '-10 10'
[]
      )";

    return fmt::vformat(str_template, args);
  }

  std::string SomethingElse()
  {
    fmt::dynamic_format_arg_store<fmt::format_context> args;
    args.push_back(fmt::arg("type", "UnstructuredMesh"));

    std::string str_template = R"(
[System]
    type = IsoVortex
    mach = 0.1
    fv = true
[]

[Executioner]
    type = Transient
    dt = 1e-03
    start_time = 0
    num_steps = 1
    end_time = 2
[]

[Outputs]
    type = VTKOutput
    file = isovortex
    interval = 100
    binary = true
    out_initial = false
[]
      )";

    return fmt::vformat(str_template, args);
  }

  void SetUp() override {}

  void SetUpConfigFile(const std::string& parallel_type)
  {
    std::ofstream config;
    config.open(_in_file);
    config << Parallel(parallel_type) << Mesh() << SomethingElse();
    config.close();
  }

  void TearDown() override {}

  bool Run()
  {
    try
    {
      int argc = 3;
      char* argv[3] = {
        " ",
        "-i",
        _in_file,
      };
      std::shared_ptr<Application> app = std::make_shared<ReMeshApp>(argc, argv);

      app->Run();

      auto& sys = app->GetSystem<IsoVortex>();
      auto sln = sys.GetSolution();
      auto result = vtkm::cont::Algorithm::Reduce(
        sys.GetSolution(), vtkm::TypeTraits<typename IsoVortex::VType>::ZeroInitialization());

      std::cout << result[0] << std::endl;
    }
    catch (const std::exception& e)
    {
      std::cout << e.what() << std::endl;
      return false;
    }
    return true;
  }

  int _argc;
  char _in_file[128] = "isovortex.i";
};

TEST_F(IsoVortexTest, res_on_centre_point)
{
  SetUpConfigFile("serial");
  EXPECT_TRUE(Run());

  SetUpConfigFile("cuda");
  EXPECT_TRUE(Run());
}
